pub mod chessboard;

///棋子颜色
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum PieceColor{
    Black,
    White
}

pub enum ChessResult{
    Ok,
    Error(u16, String)
}

#[derive(Debug, Eq, PartialEq)]
pub struct ActionResult{
    message: Option<String>,
    result: bool
}

impl ActionResult{
    pub fn success() -> ActionResult{
        ActionResult{
            message: None,
            result: true
        }
    }

    pub fn fail(message: String) -> ActionResult{
        ActionResult{
            message: Some(message),
            result: false
        }
    }

    pub fn result(&self) -> bool{
        self.result
    }

    pub fn message(&self) -> Option<String>{
        self.message.clone()
    }
}

pub struct ChessPoint{
    ///该棋子位置水平方向的棋子索引，数组存放棋子key， 0表示自己所在位置
    horizontal: [u8; 3],

    ///该棋子位置水平方向的棋子索引，数组存放棋子key, 0表示自己所在位置
    vertical: [u8; 3],

    ///棋子
    piece: Option<ChessPiece>,

    ///点序号
    index: u8,

    ///是否可用。被吃过棋子的位置是不可用的
    valid: bool
}

impl ChessPoint{
    pub fn new(index: u8, horizontal: [u8; 3], vertical: [u8; 3]) -> ChessPoint{
        ChessPoint{
            horizontal,
            vertical,
            piece: None,
            index,
            valid: true,
        }
    }

    pub fn index(&self) -> u8{
        self.index
    }

    pub fn piece(&self) -> Option<&ChessPiece>{
        match self.piece {
            None => None,
            Some(ref p) => Some(p)
        }
    }

    pub fn put_piece(&mut self, piece: ChessPiece) -> ChessResult{
        if None == self.piece{
            self.piece = Some(piece);
            ChessResult::Ok
        }else {
            ChessResult::Error(202, format!("There has piece with color {:?} already. location = {}",
                                       self.piece, self.index))
        }
    }

    pub fn remove_piece(&mut self){
        self.piece = None
    }

    pub fn pickup(&self, color: &PieceColor) -> Option<ChessPiece>{
        match self.piece {
            None => None,
            Some(ref piece) => {
                if color == piece.color(){
                    Some(piece.clone())
                }else {
                    None
                }
            }
        }
    }

    pub fn is_valid(&self) -> bool{
        self.valid
    }

    pub fn invalid_point(&mut self){
        self.valid = false
    }

    pub fn valid_point(&mut self){
        self.valid = true
    }

    pub fn horizontal(&self) -> &[u8; 3]{
        &self.horizontal
    }

    pub fn vertical(&self) -> &[u8; 3]{
        &self.vertical
    }

    pub fn clear_marker(&mut self){
        if !self.valid{
            self.valid = true
        }
    }

    ///判断当前位置是否是某种颜色的棋子。如果该位置没有棋子，返回 false
    pub fn is_piece_color(&self, color: &PieceColor) -> bool{
        match self.piece{
            None => false,
            Some(ref p) => p.color() == color
        }
    }

    ///判断两个棋子是否相邻。棋子只能走动到相邻棋子位置。
    pub fn is_near(&self, other: u8) -> bool{
        for i in 0..self.horizontal.len(){
            if other == self.horizontal[i]{
                return true;
            }
        }
        for i in 0..self.vertical.len(){
            if other == self.vertical[i]{
                return true;
            }
        }
        return false;
    }
}

#[derive(Eq, PartialEq, Debug, Clone)]
pub struct ChessPiece{
    ///颜色
    color: PieceColor,

    ///所在位置
    index: Option<u8>,

    ///是否在棋盘上
    onboard: bool
}

impl ChessPiece{
    pub fn new(color: PieceColor) -> ChessPiece{
        ChessPiece{
            color,
            index: None,
            onboard: false
        }
    }

    pub fn color(&self) -> &PieceColor{
        &self.color
    }

    pub fn index(&self) -> Option<&u8>{
        match self.index {
            None => None,
            Some(ref i) => Some(i)
        }
    }

    pub fn set_index(&mut self, index: u8){
        self.index = Some(index)
    }

    pub fn onboard(&self) -> bool{
        self.onboard
    }

    pub fn put_on(&mut self) {
        self.onboard = true
    }

    pub fn leave(&mut self){
        self.onboard = false
    }
}

#[derive(Serialize, Eq, PartialEq, Debug, Clone)]
pub struct Point{
    pub index: u32,
    pub color: String
}
